/*
 * Copyright (C) 2012, EADS France
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 */

package xowl.store.loaders;

import java.util.Arrays;

/**
 *
 * @author Laurent WOUTERS
 */
public class Lexer {
    private Automaton automaton;
    private SymbolTerminal[] terminals;
    private RewindableStream stream;
    private SymbolTerminal separator;
    private char[] buffer;
    private SymbolTerminal matchedTerminal;
    private String matchedString;
    
    public Lexer(Automaton automaton, SymbolTerminal[] terminals, RewindableStream stream, SymbolTerminal separator) {
        this.automaton = automaton;
        this.terminals = terminals;
        this.stream = stream;
        this.separator = separator;
        this.buffer = new char[RewindableStream.bufferInitSize];
    }
    
    public SymbolTerminal getMatchedTerminal() { return matchedTerminal; }
    public String getMatchedString() { return matchedString; }
    
    public String getNext() {
        if (matches())
            return matchedString;
        return null;
    }
    
    public boolean matches() {
        boolean result = executeDFA();
        while (result && matchedTerminal == separator)
            result = executeDFA();
        return result;
    }
    
    private boolean executeDFA() {
        int state = 0;
        int matchedLength = 0;
        int readCount = 0;
        
        while (state != Automaton.NO_TRANSITION) {
            int t = automaton.getTerminal(state);
            if (t != 0xFFFF) {
                matchedTerminal = terminals[t];
                matchedLength = readCount;
            }
            if (stream.isAtEnd())
                break;
            char c = stream.read();
            if (readCount == buffer.length)
                buffer = Arrays.copyOf(buffer, buffer.length * 2);
            buffer[readCount++] = c;
            state = automaton.getTransition(state, c);
        }
        stream.rewind(readCount - matchedLength);
        if (matchedLength == 0)
            return false;
        matchedString = new String(buffer, 0, matchedLength);
        return true;
    }
}
